package com.tanhua.dubbo.server.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.dubbo.config.annotation.Reference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tanhua.common.exception.BusinessException;
import com.tanhua.common.mapper.BlackListMapper;
import com.tanhua.common.mapper.UserInfoMapper;
import com.tanhua.common.pojo.BlackList;
import com.tanhua.common.pojo.User;
import com.tanhua.common.pojo.UserInfo;
import com.tanhua.common.utils.RelativeDateFormat;
import com.tanhua.common.utils.UserThreadLocal;
import com.tanhua.common.vo.ErrorResult;
import com.tanhua.dubbo.server.api.QuanZiApi;
import com.tanhua.dubbo.server.api.VisitorsApi;
import com.tanhua.dubbo.server.enums.CommentPublishIdType;
import com.tanhua.dubbo.server.enums.CommentType;
import com.tanhua.dubbo.server.pojo.Comment;
import com.tanhua.dubbo.server.pojo.Publish;
import com.tanhua.dubbo.server.pojo.Visitors;
import com.tanhua.dubbo.server.vo.CommentVo;
import com.tanhua.dubbo.server.vo.PageResult;
import com.tanhua.dubbo.server.vo.QuanZiVo;
import com.tanhua.dubbo.server.vo.VisitorsVo;
import com.tanhua.oss.OssTemplate;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Created with IntelliJ IDEA.
 *
 * @ClassName: QuanZiService
 * @Author:王晨晗
 * @Description:
 * @Date: 2021/12/30/21:47
 */
@Service
@Slf4j
public class QuanZiService {
    @Reference
    private QuanZiApi quanZiApi;

    @Autowired
    private OssTemplate ossTemplate;

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Reference
    private VisitorsApi visitorsApi;

    @Autowired
    private QuanziMQService quanziMQService;

    @Autowired
    private BlackListMapper blackListMapper;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * @param page     当前页
     * @param pagesize 每页条数
     * @description 查询好友动态信息
     * @updateTime 2021/12/30 21:51
     * @return: com.tanhua.dubbo.server.vo.PageResult
     */
    public PageResult queryPublishList(Integer page, Integer pagesize) {
        //获取user对象
        User user = UserThreadLocal.get();
        //查询黑名单列表 , 查询在我的黑名单中和我在的黑名单;
        QueryWrapper<BlackList> wrapper = new QueryWrapper<>();
        //构建条件
        wrapper.eq("user_id" , user.getId());
        //我的黑名单
        List<BlackList> blackLists = blackListMapper.selectList(wrapper);
        //黑名单用户id
        List<Object> black_user_id = CollUtil.getFieldValues(blackLists, "blackUserId");
        //查询黑名单有我的
        QueryWrapper<BlackList> wrapper1 = new QueryWrapper<>();
        //构建条件
        wrapper1.eq("black_user_id" , user.getId());
        //获取黑名单有我的集合
        List<BlackList> blackLists1 = blackListMapper.selectList(wrapper1);
        //获取用户id
        List<Object> user_id = CollUtil.getFieldValues(blackLists1, "userId");
        //合并集合
        List<Object> collect = Stream.of(black_user_id, user_id).flatMap(Collection::stream).distinct().collect(Collectors.toList());
        //获取发布动态的信息
        List<Publish> publishList = quanZiApi.queryPublishList(user.getId(), page, pagesize , collect);
        //封装pageResult对象(响应给客户端的数据)
        PageResult pageResult = new PageResult();
        pageResult.setPage(page);
        pageResult.setPagesize(pagesize);
        //判断集合是否为空
        if (CollUtil.isEmpty(publishList)) {
            return pageResult;  //集合为空,直接返回pageResult即可,表示没有好友动态
        }

        //有好友动态,进行动态封装, 封装到quanVo(因为publish中的信息不全,缺少部分信息, 需要重新封装到一个实体类)对象
        List<QuanZiVo> quanZiVoList = fillQuanZiVo(publishList);
        //将封装好的动态集合,存入pageResult中
        pageResult.setItems(quanZiVoList);
        //响应结果
        return pageResult;
    }

    //封装quanZiVo(动态的信息)对象

    /**
     * @param publishList 动态列表
     * @return
     * @description 封装quanZiVo对象;
     */
    public List<QuanZiVo> fillQuanZiVo(List<Publish> publishList) {
        //创建集合,保存动态信息
        List<QuanZiVo> quanZiVoList = new ArrayList<>();
        //遍历动态集合
        for (Publish publish : publishList) {
            //创建quanZiVo对象
            QuanZiVo quanZiVo = new QuanZiVo();
            quanZiVo.setId(publish.getId().toHexString());      //动态id
            quanZiVo.setTextContent(publish.getText());         //动态文字内容
            quanZiVo.setImageContent(publish.getMedias().toArray(new String[]{}));      //动态图片内容
            quanZiVo.setUserId(publish.getUserId());        //发布动态者id
            quanZiVo.setCreateDate(RelativeDateFormat.format(new Date(publish.getCreated())));      //发布时间

            //添加至集合
            quanZiVoList.add(quanZiVo);
        }

        //获取动态信息集合中的用户id
        List<Object> userIdList = CollUtil.getFieldValues(publishList, "userId");
        //查询动态集合中的每一位用户的详细信息
        LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(UserInfo::getId, userIdList);
        List<UserInfo> userInfoList = userInfoMapper.selectList(wrapper);

        //封装用户详细信息到quanZiVo对象中
        for (QuanZiVo quanZiVo : quanZiVoList) {
            for (UserInfo userInfo : userInfoList) {
                if (quanZiVo.getUserId().longValue() == userInfo.getUserId().longValue()) {
                    //调用填充用户信息方法 ,补全quanZiVo的数据
                    fillUserInfoToQuanZiVo(userInfo, quanZiVo);
                    break;
                }
            }
        }
        //返回quanziVo对象集合
        return quanZiVoList;
    }

    /**
     * @param userInfo 用户详细信息
     * @param quanZiVo 响应前端的动态信息数据
     * @return
     * @description 为quanZiVo填充用户的信息
     */
    private void fillUserInfoToQuanZiVo(UserInfo userInfo, QuanZiVo quanZiVo) {
        //调用hutool根据自动填充两个对象中相同属性的值, (排除id)
        BeanUtil.copyProperties(userInfo, quanZiVo, "id");
        //对于无法映射的属性,进行手动处理
        quanZiVo.setGender(userInfo.getSex().name().toLowerCase(Locale.ROOT));          //性别
        quanZiVo.setTags(StringUtils.split(userInfo.getTags(), ","));        //标签
        //获取用户id
        User user = UserThreadLocal.get();

        //此处数据后续处理
        quanZiVo.setCommentCount(Convert.toInt(quanZiApi.queryCount(quanZiVo.getId(), CommentType.COMMENT))); // 评论数
        quanZiVo.setDistance("1.2公里"); //TODO 距离
        quanZiVo.setHasLiked(quanZiApi.queryUserIf(user.getId(), quanZiVo.getId(), CommentType.LIKE) ? 1 : 0); //是否点赞（1是，0否）
        quanZiVo.setLikeCount(Convert.toInt(quanZiApi.queryCount(quanZiVo.getId(), CommentType.LIKE))); // 点赞数
        quanZiVo.setHasLoved(quanZiApi.queryUserIf(user.getId(), quanZiVo.getId(), CommentType.LOVE) ? 1 : 0); // 是否喜欢（1是，0否）
        quanZiVo.setLoveCount(Convert.toInt(quanZiApi.queryCount(quanZiVo.getId(), CommentType.LOVE))); // 喜欢数
    }

    /**
     * @param page
     * @param pagesize
     * @description 查询推荐动态
     * @updateTime 2021/12/30 23:11
     */
    public PageResult queryRecomendPublishList(Integer page, Integer pagesize) {
        //获取user对象
        User user = UserThreadLocal.get();
        //查询推荐动态列表
        List<Publish> publishList = quanZiApi.queryRecommendPublishList(user.getId(), page, pagesize);

        //封装响应的vo对象
        PageResult pageResult = new PageResult();
        pageResult.setPage(page);       //当前页
        pageResult.setPagesize(pagesize);  //每页条数

        //判断推荐动态的集合是否为空
        if (CollUtil.isEmpty(publishList)) {
            return pageResult;      //为空直接返回pageResult
        }

        //有推荐动态,进行动态封装, 封装到quanVo(因为publish中的信息不全,缺少部分信息, 需要重新封装到一个实体类)对象
        List<QuanZiVo> quanZiVoList = fillQuanZiVo(publishList);
        //将封装好的动态集合,存入pageResult中
        pageResult.setItems(quanZiVoList);
        //响应结果
        return pageResult;
    }

    /**
     * @param textContent    文字内容
     * @param multipartFiles 图片集合
     * @param location       位置
     * @param longitude      经度
     * @param latitude       维度
     * @description 发布动态
     * @updateTime 2021/12/31 10:03
     */
    public String savePublish(String textContent, MultipartFile[] multipartFiles, String location, String longitude, String latitude) {
        //获取user对象
        User user = UserThreadLocal.get();

        //查询是否有冻结
        String redisKey = "USER_FREEZE_" + user.getId();
        String data = redisTemplate.opsForValue().get(redisKey);
        //有冻结
        if (ObjectUtil.isNotEmpty(data)) {
            //判断是否是登陆冻结
            if (StringUtils.equals(data, "3")) {
               throw new BusinessException(ErrorResult.FreezeSavePublish());
            }
        }

        //封装publish动态信息
        Publish publish = new Publish();

        publish.setUserId(user.getId());        //发布者id
        publish.setText(textContent);           //发布文字内容
        publish.setLocationName(location);      //地址
        publish.setLatitude(latitude);          //经度
        publish.setLongitude(longitude);        //维度
        publish.setSeeType(1);                  //可见类型

        //图片上传
        List<String> picUrls = new ArrayList<>();
        //遍历文件数组
        for (MultipartFile file : multipartFiles) {
            //上传图片 , 获取文件地址
            String filePath = ossTemplate.uploadFile(file);
            //不为空, 保存图片地址
            if (StrUtil.isNotBlank(filePath)) {
                picUrls.add(filePath);      //todo 为空时可进行异常抛出 , 此处暂不进行异常抛出
            }
        }

        publish.setMedias(picUrls);     //图片地址数组

        //执行保存publish , 返回动态id
        String publishId = quanZiApi.savePublish(publish);
        //判断是否为空,判断保存结果
        if (StrUtil.isEmpty(publishId)) {
            throw new BusinessException(ErrorResult.savePublishError());        //保存失败
        } else {
            //发送消息
            quanziMQService.publishMsg(publishId);
        }
        return null;
    }


    /**
     * @param publishId            动态的id
     * @param commentPublishIdType publishId的类型: 动态/视频/评论
     * @return 动态的点赞数
     * @description 动态点赞功能
     */
    public Long likeComment(String publishId, CommentPublishIdType commentPublishIdType) {
        //获取用户信息
        User user = UserThreadLocal.get();
        //调用quanziApi接口的点赞/喜欢方法 , 评论点类型:like , 保存类型:动态的点赞
        Boolean result = quanZiApi.likeOrLoveComment(user.getId(), publishId, CommentType.LIKE, commentPublishIdType);
        if (result) {    //如果点赞成功,获取点赞数,返回前端
            //发消息
            quanziMQService.likePublishMsg(publishId);
            return quanZiApi.queryCount(publishId, CommentType.LIKE);
        }
        throw new BusinessException(ErrorResult.likeCommentError());  //点赞失败
    }

    /**
     * @param publishId 动态id
     * @return
     * @description 动态取消点赞
     */
    public Long disLikeComment(String publishId) {
        //获取user信息
        User user = UserThreadLocal.get();
        //调用取消点赞/喜欢方法,参数:评论类型
        Boolean result = quanZiApi.disLikeOrLove(user.getId(), publishId, CommentType.LIKE);
        if (result) {    //如果取消点赞成功,获取点赞数,返回前端
            quanziMQService.disLikePublishMsg(publishId);
            return quanZiApi.queryCount(publishId, CommentType.LIKE);
        }
        return null;
    }

    /**
     * @param publishId 动态的id
     * @return 动态的喜欢数
     * @description 动态喜欢功能
     */
    public Long loveComment(String publishId) {
        //获取user信息
        User user = UserThreadLocal.get();
        //调用quanziApi接口的点赞/喜欢方法 , 评论类型:love , 保存类型:动态的点赞
        Boolean result = quanZiApi.likeOrLoveComment(user.getId(), publishId, CommentType.LOVE, CommentPublishIdType.PUBLISH);
        if (result) {    //如果喜欢成功,获取喜欢数,返回前端
            //发消息
            quanziMQService.lovePublishMsg(publishId);
            return quanZiApi.queryCount(publishId, CommentType.LOVE);
        }
        return null;        //todo 此处抛出异常
    }

    /**
     * @param publishId 动态id
     * @return
     * @description 取消喜欢
     */
    public Long disLoveComment(String publishId) {
        //获取用户信息
        User user = UserThreadLocal.get();
        //调用取消点赞/喜欢方法,参数:评论类型 love
        Boolean result = quanZiApi.disLikeOrLove(user.getId(), publishId, CommentType.LOVE);
        if (result) {    //如果取消喜欢成功,获取喜欢数,返回前端
            //发消息
            quanziMQService.disLovePublishMsg(publishId);
            return quanZiApi.queryCount(publishId, CommentType.LOVE);
        }
        return null;
    }

    /**
     * @param publishId 动态id
     * @return
     * @description 查看单条动态
     */
    public QuanZiVo queryById(String publishId) {
        //查询动态信息
        Publish publish = quanZiApi.queryPublishById(publishId);
        //发消息
        quanziMQService.queryPublishMsg(publishId);
        //判断动态是否为空, 不为空封装quanZivo对象;
        return publish == null ? null : fillQuanZiVo(Arrays.asList(publish)).get(0);
    }

    /**
     * @param publishId 动态id
     * @param page      当前页
     * @param pageSize  每页条数
     * @return
     * @description 获取评论列表
     */
    public PageResult queryCommentList(String publishId, Integer page, Integer pageSize) {
        //获取user对象
        User user = UserThreadLocal.get();
        //封装pageresult
        PageResult pageResult = new PageResult();
        pageResult.setPagesize(pageSize);
        pageResult.setPage(page);
        //查询评论列表
        List<Comment> commentList = quanZiApi.queryCommentList(publishId, page, pageSize);
        //判断查询是否成功
        if (CollUtil.isEmpty(commentList)) {
            return pageResult;      //为空 , 直接返回
        }

        //封装评论实体类所需信息
        //查询对应评论的用户的详细信息
        List<Object> userIds = CollUtil.getFieldValues(commentList, "userId");
        LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(UserInfo::getId, userIds);
        List<UserInfo> userInfoList = userInfoMapper.selectList(wrapper);

        //封装commentVo对象
        List<CommentVo> result = new ArrayList<>();
        for (Comment comment : commentList) {
            //创建CommentVO对象
            CommentVo commentVo = new CommentVo();
            commentVo.setContent(comment.getContent());         //评论内容
            commentVo.setId(comment.getId().toHexString());     //评论id
            commentVo.setCreateDate(DateUtil.format(new Date(comment.getCreated()), "HH:mm"));     //评论时间
            commentVo.setHasLiked(quanZiApi.queryUserIf(user.getId(), commentVo.getId(), CommentType.LIKE) ? 1 : 0);    //当前用户是否点赞
            commentVo.setLikeCount(Convert.toInt(quanZiApi.queryCount(commentVo.getId(), CommentType.LIKE)));  //该评论的点赞数

            //封装用户详细信息
            for (UserInfo userInfo : userInfoList) {
                if (ObjectUtil.equals(comment.getUserId(), userInfo.getUserId())) {
                    commentVo.setAvatar(userInfo.getLogo());            //头像
                    commentVo.setNickname(userInfo.getNickName());      //昵称
                    break;
                }
            }
            //添加的集合
            result.add(commentVo);
        }
        //封装集合到pageResult对象
        pageResult.setItems(result);
        //获取评论条数
        pageResult.setCounts(Convert.toInt(quanZiApi.queryCount(publishId, CommentType.COMMENT)));
        //返回结果
        return pageResult;
    }


    /**
     * @param publishId            动态/视频的id
     * @param content              评论内容
     * @param commentPublishIdType publishId的类型,是动态的评论还是视频的评论
     * @return
     * @description 保存发表的评论
     */
    public Boolean saveComments(String publishId, String content, CommentPublishIdType commentPublishIdType) {
        //获取用户信息
        User user = UserThreadLocal.get();

        //查询是否有冻结
        String redisKey = "USER_FREEZE_" + user.getId();
        String data = redisTemplate.opsForValue().get(redisKey);
        //有冻结
        if (ObjectUtil.isNotEmpty(data)) {
            //判断是否是登陆冻结
            if (StringUtils.equals(data, "2")) {
                throw new BusinessException(ErrorResult.commentFreezeFail());
            }
        }
        //保存评论
        Boolean result = quanZiApi.saveComment(user.getId(), publishId, content, commentPublishIdType);
        if (result) {
            //发消息
            quanziMQService.commentPublishMsg(publishId);
        }
        return result;
    }

    /**
     * @param userId
     * @param page
     * @param pageSize
     * @return
     * @description 查询个人的所有动态
     */
    public PageResult queryAlbumList(Long userId, Integer page, Integer pageSize) {
        //封装PageResult对象
        PageResult pageResult = new PageResult();
        pageResult.setPage(page);
        pageResult.setPagesize(pageSize);

        //查询动态数据
        List<Publish> publishList = quanZiApi.queryAlbumList(userId, page, pageSize);

        if (CollUtil.isEmpty(publishList)) {
            return pageResult;
        }

        //填充数据
        pageResult.setItems(fillQuanZiVo(publishList));

        //响应数据
        return pageResult;
    }

    /**
     * @return
     * @description 谁看过我
     */
    public List<VisitorsVo> queryVisitorList() {
        //获取用户信息
        User user = UserThreadLocal.get();
        //获取访客集合信息
        List<Visitors> visitorsList = visitorsApi.queryMyVisitor(user.getId());
        //为空 返回空集合
        if (CollUtil.isEmpty(visitorsList)) {
            return Collections.emptyList();
        }

        //获取访客记录的访问者id
        List<Object> userIds = CollUtil.getFieldValues(visitorsList, "visitorUserId");
        //查询数据库 获取用户详细信息
        QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
        wrapper.in("user_id", userIds);
        List<UserInfo> userInfoList = userInfoMapper.selectList(wrapper);

        //遍历访客集合,封装响应数据
        List<VisitorsVo> visitorsVoList = new ArrayList<>();
        for (Visitors visitor : visitorsList) {
            for (UserInfo userInfo : userInfoList) {
                if (ObjectUtil.equals(visitor.getVisitorUserId(), userInfo.getUserId())) {
                    VisitorsVo visitorsVo = new VisitorsVo();
                    visitorsVo.setAge(userInfo.getAge());       //年龄
                    visitorsVo.setAvatar(userInfo.getLogo());   //头像
                    visitorsVo.setGender(userInfo.getSex().name().toLowerCase());   //性别
                    visitorsVo.setId(userInfo.getUserId());     //id
                    visitorsVo.setNickname(userInfo.getNickName());     //昵称
                    visitorsVo.setTags(StringUtils.split(userInfo.getTags(), ','));     //标签
                    visitorsVo.setFateValue(visitor.getScore().intValue());     //缘分值

                    visitorsVoList.add(visitorsVo);
                    break;
                }
            }
        }

        return visitorsVoList;
    }
}
